home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / sys5login.c < prev    next >
C/C++ Source or Header  |  1992-02-10  |  14KB  |  580 lines

  1. #include <sys/types.h>
  2.  
  3. #include <stdio.h>      /* must be before pwd.h */
  4.  
  5. #include <ctype.h>
  6. #include <errno.h>
  7. #include <fcntl.h>
  8. #include <pwd.h>
  9. #include <signal.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <time.h>
  13. #ifdef SPASSWD
  14. #include <shadow.h>
  15. #endif
  16. #include <sys/stat.h>
  17. #include <termio.h>
  18. #include <unistd.h>
  19. #include <utmp.h>
  20.  
  21. #include "global.h"
  22. #include "mbuf.h"
  23. #include "timer.h"
  24. #include "hpux.h"
  25. #include "telnet.h"
  26. #include "login.h"
  27.  
  28. extern struct utmp *getutent();
  29. extern struct utmp *getutid();
  30. extern void endutent();
  31. extern void pututline();
  32.  
  33. #define MASTERPREFIX        "/dev/pty"
  34. #define SLAVEPREFIX         "/dev/tty"
  35. #define NUMPTY            16
  36.  
  37. #define PASSWDFILE          "/etc/passwd"
  38. #define PWLOCKFILE          "/etc/ptmp"
  39.  
  40. #define DEFAULTUSER         "guest"
  41. #define FIRSTUID            400
  42. #define MAXUID              4095
  43. #define GID                 400
  44. #define HOMEDIRPARENTPARENT "/users/funk"
  45.  
  46. /* login server control block */
  47.  
  48. struct login_cb {
  49.   int  pty;                     /* pty file descriptor */
  50.   int  num;                     /* pty number */
  51.   char  id[4];                  /* pty id (last 2 chars) */
  52.   int  pid;                     /* process id of login process */
  53.   char  inpbuf[512];            /* pty read buffer */
  54.   char  *inpptr;                /* pty read buffer pointer */
  55.   int  inpcnt;                  /* pty read buffer count */
  56.   struct mbuf *sndq;            /* pty send queue */
  57.   int  lastchr;                 /* last chr fetched from send queue */
  58.   int  linelen;                 /* counter for automatic line break */
  59.   char  outbuf[256];            /* pty write buffer */
  60.   char  *outptr;                /* pty write buffer pointer */
  61.   int  outcnt;                  /* pty write buffer count */
  62.   void (*readfnc) __ARGS((void *fncarg));
  63.                 /* func to call if pty is readable */
  64.   void (*closefnc) __ARGS((void *fncarg));
  65.                 /* func to call if pty gets closed */
  66.   void  *fncarg;                /* argument for readfnc and closefnc */
  67.   int  telnet;                  /* telnet mode */
  68.   int  state;                   /* telnet state */
  69.   char  option[NOPTIONS+1];     /* telnet options */
  70. };
  71.  
  72. static int32 pty_locktime[NUMPTY];
  73.  
  74. static int find_pty __ARGS((int *numptr, char *slave));
  75. static void restore_pty __ARGS((char *id));
  76. static void write_log_header __ARGS((int fd, char *user, char *protocol));
  77. static int do_telnet __ARGS((struct login_cb *tp, int chr));
  78. static void write_pty __ARGS((struct login_cb *tp));
  79. static void excp_handler __ARGS((struct login_cb *tp));
  80.  
  81. /*---------------------------------------------------------------------------*/
  82.  
  83. #define pty_name(name, prefix, num) \
  84.   sprintf(name, "%s%c%x", prefix, 'p' + (num >> 4), num & 0xf)
  85.  
  86. /*---------------------------------------------------------------------------*/
  87. static int find_pty(numptr, slave)
  88. int *numptr;
  89. char *slave;
  90. {
  91.  
  92.   char master[80];
  93.   int fd, num;
  94.  
  95.   for (num = 0; num < NUMPTY; num++)
  96.     if (pty_locktime[num] < secclock()) {
  97.       pty_locktime[num] = secclock() + 60;
  98.       pty_name(master, MASTERPREFIX, num);
  99.       if ((fd = open(master, O_RDWR | O_NDELAY, 0600)) >= 0) {
  100.     *numptr = num;
  101.     pty_name(slave, SLAVEPREFIX, num);
  102.     return fd;
  103.       }
  104.     }
  105.   return (-1);
  106. }
  107. /*---------------------------------------------------------------------------*/
  108.  
  109. static void restore_pty(id)
  110. char  *id;
  111. {
  112.   char  filename[80];
  113.  
  114.   sprintf(filename, "%s%s", MASTERPREFIX, id);
  115.   chown(filename, 0, 0);
  116.   chmod(filename, 0666);
  117.   sprintf(filename, "%s%s", SLAVEPREFIX, id);
  118.   chown(filename, 0, 0);
  119.   chmod(filename, 0666);
  120. }
  121.  
  122. /*---------------------------------------------------------------------------*/
  123.  
  124. void fixutmpfile()
  125. {
  126.   register struct utmp *up;
  127.  
  128.   while (up = getutent())
  129.     if (up->ut_type == USER_PROCESS && kill(up->ut_pid, 0)) {
  130.       restore_pty(up->ut_id);
  131.       up->ut_user[0] = '\0';
  132.       up->ut_type = DEAD_PROCESS;
  133.       up->ut_exit.e_termination = 0;
  134.       up->ut_exit.e_exit = 0;
  135.       up->ut_time = secclock();
  136.       pututline(up);
  137.     }
  138.   endutent();
  139. }
  140.  
  141. /*---------------------------------------------------------------------------*/
  142.  
  143. struct passwd *getpasswdentry(name, create)
  144. char  *name;
  145. int  create;
  146. {
  147.  
  148.   FILE * fp;
  149.   char  *cp;
  150.   char  bitmap[MAXUID+1];
  151.   char  homedir[80];
  152.   char  homedirparent[80];
  153.   char  username[128];
  154.   int  fd;
  155.   int  uid;
  156.   struct passwd *pw;
  157. #ifdef SPASSWD
  158.   struct spwd *sw;
  159. #endif
  160.  
  161.   /* Fix user name */
  162.  
  163.   for (cp = username; isalnum(uchar(*name)); *cp++ = tolower(uchar(*name++))) ;
  164.   *cp = '\0';
  165.   if (!isalpha(uchar(*username)) || strlen(username) > 8)
  166.     strcpy(username, DEFAULTUSER);
  167.  
  168.   /* Search existing passwd entry */
  169.  
  170.   while ((pw = getpwent()) && strcmp(username, pw->pw_name)) ;
  171.   endpwent();
  172. #ifdef SPASSWD
  173.   while ((sw = getspent()) && strcmp(username, sw->sp_namp)) ;
  174.   endspent();
  175.   if (sw) 
  176.   pw->pw_passwd = sw->sp_pwdp;
  177. #endif
  178.   if (pw) return pw;
  179.   if (!create) return 0;
  180.  
  181.   /* Find free user id */
  182.  
  183.   if ((fd = open(PWLOCKFILE, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) return 0;
  184.   close(fd);
  185.   memset(bitmap, 0, sizeof(bitmap));
  186.   while (pw = getpwent()) {
  187.     if (!strcmp(username, pw->pw_name)) break;
  188.     if (pw->pw_uid <= MAXUID) bitmap[pw->pw_uid] = 1;
  189.   }
  190.   endpwent();
  191.   if (pw) {
  192.     unlink(PWLOCKFILE);
  193.     return pw;
  194.   }
  195.   for (uid = FIRSTUID; uid <= MAXUID && bitmap[uid]; uid++) ;
  196.   if (uid > MAXUID) {
  197.     unlink(PWLOCKFILE);
  198.     return 0;
  199.   }
  200.  
  201.   /* Add user to passwd file */
  202.  
  203.   sprintf(homedirparent, "%s/%.3s...", HOMEDIRPARENTPARENT, username);
  204.   sprintf(homedir, "%s/%s", homedirparent, username);
  205.   if (!(fp = fopen(PASSWDFILE, "a"))) {
  206.     unlink(PWLOCKFILE);
  207.     return 0;
  208.   }
  209. #ifdef SPASSWD
  210.   fprintf(fp, "%s:x:%d:%d::%s:/bin/sh\n", username, uid, GID, homedir);
  211. #else
  212.   fprintf(fp, "%s:,./:%d:%d::%s:/bin/sh\n", username, uid, GID, homedir);
  213. #endif
  214.   fclose(fp);
  215.   pw = getpwuid(uid);
  216.   endpwent();
  217.   unlink(PWLOCKFILE);
  218.  
  219. #ifdef SPASSWD
  220.   if ((fd = open(SHADTEMP, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) return 0;
  221.   close(fd);
  222.  
  223.   /* Add user to Shadow file */
  224.  
  225.    if (!(fp = fopen(SHADOW, "a"))) {
  226.    unlink(SHADTEMP);
  227.    return 0;
  228.    }
  229.    
  230.   fprintf(fp, "%s::%d:%d:%d\n", username, 7676,10000,10000); /** 7676 = expire time ?! **/
  231.   fclose(fp);
  232.   unlink(SHADTEMP);
  233.   pw->pw_passwd= "\0";  /** to avoid another getspent call **/ 
  234.  
  235. #endif /* SPASSWD */
  236.  
  237.   /* Create home directory */
  238.  
  239.   mkdir(homedirparent, 0755);
  240.   mkdir(homedir, 0755);
  241.   chown(homedir, uid, GID);
  242.   return pw;
  243. }
  244.  
  245. /*---------------------------------------------------------------------------*/
  246.  
  247. static void write_log_header(fd, user, protocol)
  248. int  fd;
  249. char  *user, *protocol;
  250. {
  251.  
  252.   char  buf[1024];
  253.   struct tm *tm;
  254.  
  255.   tm = localtime((long *) &Secclock);
  256.   sprintf(buf,
  257.       "%s at %2d-%.3s-%02d %2d:%02d:%02d by %s\n",
  258.       protocol,
  259.       tm->tm_mday,
  260.       "JanFebMarAprMayJunJulAugSepOctNovDec" + 3 * tm->tm_mon,
  261.       tm->tm_year % 100,
  262.       tm->tm_hour,
  263.       tm->tm_min,
  264.       tm->tm_sec,
  265.       user);
  266.   write_log(fd, buf, (int) strlen(buf));
  267. }
  268.  
  269. /*---------------------------------------------------------------------------*/
  270.  
  271. static int  do_telnet(tp, chr)
  272. struct login_cb *tp;
  273. int  chr;
  274. {
  275.   struct termio termio;
  276.  
  277.   switch (tp->state) {
  278.   case TS_DATA:
  279.     if (chr != IAC) {
  280.       /*** if (!tp->option[TN_TRANSMIT_BINARY]) chr &= 0x7f; ***/
  281.       return 1;
  282.     }
  283.     tp->state = TS_IAC;
  284.     break;
  285.   case TS_IAC:
  286.     switch (chr) {
  287.     case WILL:
  288.       tp->state = TS_WILL;
  289.       break;
  290.     case WONT:
  291.       tp->state = TS_WONT;
  292.       break;
  293.     case DO:
  294.       tp->state = TS_DO;
  295.       break;
  296.     case DONT:
  297.       tp->state = TS_DONT;
  298.       break;
  299.     case IAC:
  300.       tp->state = TS_DATA;
  301.       return 1;
  302.     default:
  303.       tp->state = TS_DATA;
  304.       break;
  305.     }
  306.     break;
  307.   case TS_WILL:
  308.     tp->state = TS_DATA;
  309.     break;
  310.   case TS_WONT:
  311.     tp->state = TS_DATA;
  312.     break;
  313.   case TS_DO:
  314.     if (chr <= NOPTIONS) tp->option[chr] = 1;
  315.     if (chr == TN_ECHO) {
  316.       ioctl(tp->pty, TCGETA, &termio);
  317.       termio.c_lflag |= (ECHO | ECHOE);
  318.       ioctl(tp->pty, TCSETA, &termio);
  319.     }
  320.     tp->state = TS_DATA;
  321.     break;
  322.   case TS_DONT:
  323.     if (chr <= NOPTIONS) tp->option[chr] = 0;
  324.     if (chr == TN_ECHO) {
  325.       ioctl(tp->pty, TCGETA, &termio);
  326.       termio.c_lflag &= ~(ECHO | ECHOE);
  327.       ioctl(tp->pty, TCSETA, &termio);
  328.     }
  329.     tp->state = TS_DATA;
  330.     break;
  331.   }
  332.   return 0;
  333. }
  334.  
  335. /*---------------------------------------------------------------------------*/
  336.  
  337. static void write_pty(tp)
  338. struct login_cb *tp;
  339. {
  340.  
  341.   char  *p;
  342.   char  buf[256];
  343.   int  chr;
  344.   int  cnt;
  345.   int  lastchr;
  346.  
  347.   p = buf;
  348.   while ((chr = PULLCHAR(&tp->sndq)) != -1) {
  349.     lastchr = tp->lastchr;
  350.     tp->lastchr = chr;
  351.     if (!tp->telnet || do_telnet(tp, uchar(chr))) {
  352.       if (lastchr != '\r' || chr != '\0' && chr != '\n') {
  353.     *p++ = chr;
  354.     if (chr == '\r' || chr == '\n') {
  355.       tp->linelen = 0;
  356.       break;
  357.     }
  358.     if (++tp->linelen >= 250) {
  359.       *p++ = '\n';
  360.       tp->linelen = 0;
  361.       break;
  362.     }
  363.       }
  364.     }
  365.   }
  366.   if (cnt = p - buf) {
  367.     write(tp->pty, buf, (unsigned) cnt);
  368.     write_log(tp->pty, buf, cnt);
  369.   }
  370.   if (!tp->sndq) off_write(tp->pty);
  371. }
  372.  
  373. /*---------------------------------------------------------------------------*/
  374.  
  375. static void excp_handler(tp)
  376. struct login_cb *tp;
  377. {
  378.  
  379.     if(is_dead(tp)){
  380.     off_read(tp->pty);
  381.     off_write(tp->pty);
  382.     off_excp(tp->pty);
  383.     if (tp->closefnc) (*tp->closefnc)(tp->fncarg);
  384.     }
  385. }
  386.  
  387. /*---------------------------------------------------------------------------*/
  388.  
  389. struct login_cb *login_open(user, protocol, read_upcall, close_upcall, upcall_arg)
  390. char  *user, *protocol;
  391. void (*read_upcall) __ARGS((void *arg));
  392. void (*close_upcall) __ARGS((void *arg));
  393. void  *upcall_arg;
  394. {
  395.  
  396.   char  *env = 0;
  397.   char  slave[80];
  398.   int  i;
  399.   struct login_cb *tp;
  400.   struct passwd *pw;
  401.   struct termio termio;
  402.   struct utmp utmp;
  403.  
  404.   tp = (struct login_cb *) calloc(1, sizeof(struct login_cb ));
  405.   if (!tp) return 0;
  406.   tp->telnet = !strcmp(protocol, "TELNET");
  407.   if ((tp->pty = find_pty(&tp->num, slave)) < 0) {
  408.     free(tp);
  409.     return 0;
  410.   }
  411.   strcpy(tp->id, slave + strlen(slave) - 2);
  412.   tp->readfnc = read_upcall;
  413.   tp->closefnc = close_upcall;
  414.   tp->fncarg = upcall_arg;
  415.   on_read(tp->pty, tp->readfnc, tp->fncarg);
  416.   on_excp(tp->pty, (void (*)()) excp_handler, tp);
  417.   i = 1;
  418.   write_log_header(tp->pty, user, protocol);
  419.   if (!(tp->pid = fork())) {
  420.     pw = getpasswdentry(user, 1);
  421.     if (!pw || pw->pw_passwd[0]) pw = getpasswdentry("", 0);
  422.     for (i = 0; i < _NFILE; i++) close(i);
  423.     setpgrp();
  424.     open(slave, O_RDWR, 0666);
  425.     dup(0);
  426.     dup(0);
  427.     chmod(slave, 0622);
  428.     memset(&termio, 0, sizeof(termio));
  429.     termio.c_iflag = ICRNL | IXOFF;
  430.     termio.c_oflag = OPOST | ONLCR | TAB3;
  431.     termio.c_cflag = B1200 | CS8 | CREAD | CLOCAL;
  432.     termio.c_lflag = ISIG | ICANON;
  433.     termio.c_cc[VINTR]  = 127;
  434.     termio.c_cc[VQUIT]  =  28;
  435.     termio.c_cc[VERASE] =   8;
  436.     termio.c_cc[VKILL]  =  24;
  437.     termio.c_cc[VEOF]   =   4;
  438.     ioctl(0, TCSETA, &termio);
  439.     ioctl(0, TCFLSH, 2);
  440.     if (!pw || pw->pw_passwd[0]) exit(1);
  441.     memset(&utmp, 0, sizeof(utmp));
  442.     strcpy(utmp.ut_user, "LOGIN");
  443.     strcpy(utmp.ut_id, tp->id);
  444.     strcpy(utmp.ut_line, slave + 5);
  445.     utmp.ut_pid = getpid();
  446.     utmp.ut_type = LOGIN_PROCESS;
  447.     utmp.ut_time = secclock();
  448. #ifdef _UTMP_INCLUDED   /* maybe in a later version of sys5 3.2 or rel 4 ?*/
  449.     strncpy(utmp.ut_host, protocol, sizeof(utmp.ut_host));
  450. #endif
  451.     pututline(&utmp);
  452.     endutent();
  453.     execle("/bin/login", "login", pw->pw_name, (char *) 0, &env);
  454.    exit(1);
  455.   }
  456.   return tp;
  457. }
  458.  
  459. /*---------------------------------------------------------------------------*/
  460. void login_close(tp)
  461. struct login_cb *tp;
  462. {
  463.  
  464.   int  fwtmp;
  465.   struct utmp utmp, *up;
  466.  
  467.   if (!tp) return;
  468.   if (tp->pty > 0) {
  469.     off_read(tp->pty);
  470.     off_write(tp->pty);
  471.     off_excp(tp->pty);
  472.     close(tp->pty);
  473.     restore_pty(tp->id);
  474.     pty_locktime[tp->num] = 0;
  475.     write_log(tp->pty, (char *) 0, -1);
  476.   }
  477.   if (tp->pid > 0) {
  478.     kill(-tp->pid, SIGHUP);
  479.     memset(&utmp, 0, sizeof(utmp));
  480.     strcpy(utmp.ut_id, tp->id);
  481.     utmp.ut_type = DEAD_PROCESS;
  482.     if (up = getutid(&utmp)) {
  483.       up->ut_user[0] = '\0';
  484.       up->ut_type = DEAD_PROCESS;
  485.       up->ut_exit.e_termination = 0;
  486.       up->ut_exit.e_exit = 0;
  487.       up->ut_time = secclock();
  488.       memcpy(&utmp, up, sizeof(utmp));
  489.       pututline(up);
  490.       fwtmp = open("/etc/wtmp", O_WRONLY | O_CREAT | O_APPEND, 0644);
  491.       write(fwtmp, (char *) &utmp, sizeof(utmp));
  492.       close(fwtmp);
  493.     }
  494.     endutent();
  495.   }
  496.   free_q(&tp->sndq);
  497.   free(tp);
  498. }
  499. /*---------------------------------------------------------------------------*/
  500.  
  501. #define ASIZE 512
  502.  
  503. #define add_to_mbuf(chr) \
  504. { \
  505.   if (!head) head = tail = alloc_mbuf(ASIZE); \
  506.   if (tail->cnt >= ASIZE) tail = tail->next = alloc_mbuf(ASIZE); \
  507.   tail->data[tail->cnt++] = chr; \
  508.   cnt--; \
  509. }
  510.  
  511. /*---------------------------------------------------------------------------*/
  512.  
  513.  
  514. struct mbuf *login_read(tp, cnt)
  515. struct login_cb *tp;
  516. int  cnt;
  517. {
  518.  
  519.   int  chr;
  520.   struct mbuf *head, *tail;
  521.  
  522.   if (cnt <= 0) {
  523.     off_read(tp->pty);
  524.     if(is_dead(tp)){  /* Not every time an exeption, so check it again */
  525.     off_read(tp->pty);
  526.     off_write(tp->pty);
  527.     off_excp(tp->pty);
  528.     if (tp->closefnc) (*tp->closefnc)(tp->fncarg);
  529.    }
  530.     return 0;
  531.   }
  532.   on_read(tp->pty, tp->readfnc, tp->fncarg); 
  533.     if(is_dead(tp)){  /* Not every time an exeption, so check it again */
  534.     off_read(tp->pty);
  535.     off_write(tp->pty);
  536.     off_excp(tp->pty);
  537.     if (tp->closefnc) (*tp->closefnc)(tp->fncarg);
  538.    }
  539.   head = 0;
  540.   while (cnt) {
  541.     if (tp->inpcnt <= 0) {
  542.       if ((tp->inpcnt = read(tp->pty, tp->inpptr = tp->inpbuf, sizeof(tp->inpbuf))) <= 0)
  543.     return head;
  544.       write_log(tp->pty, tp->inpbuf, tp->inpcnt);
  545.     }
  546.     tp->inpcnt--;
  547.     chr = uchar(*tp->inpptr++);
  548.     if (chr == 0x11 || chr == 0x13) {
  549.       /* ignore XON / XOFF */
  550.     } else if (tp->telnet) {
  551.       add_to_mbuf(chr);
  552.       if (chr == IAC) add_to_mbuf(IAC);
  553.     } else {
  554.       if (chr != '\n') add_to_mbuf(chr);
  555.     }
  556.   }
  557.   return head;
  558. }
  559.  
  560. /*---------------------------------------------------------------------------*/
  561.  
  562. void login_write(tp, bp)
  563. struct login_cb *tp;
  564. struct mbuf *bp;
  565. {
  566.   append(&tp->sndq, bp);
  567.   on_write(tp->pty, (void (*)()) write_pty, tp);
  568.   if (tp->linelen) write_pty(tp);
  569. }
  570.  
  571. /*---------------------------------------------------------------------------*/
  572.  
  573. /* check for login process dead */
  574. int
  575. is_dead(tp)
  576.     struct login_cb *tp; {
  577.  
  578.     return kill(tp->pid, 0);
  579. }
  580.